﻿using Geek.Server.App.Common.Session;
using Geek.Server.App.Logic.Login;
using Geek.Server.Core.Actors;
using Geek.Server.Core.Hotfix.Agent;
using Geek.Server.Core.Net;
using Geek.Server.Core.Utils;
using Server.Logic.Common.Handler;
using Server.Logic.Common.Utils;
using Server.Logic.Logic.Role.Base;
using Server.Logic.Logic.Server;

namespace Server.Logic.Login
{
    public partial class LoginCompAgent : StateCompAgent<LoginComp, LoginState>
    {
        private static readonly Logger Log = LogManager.GetCurrentClassLogger();

        /// <summary>
        /// 登陆请求处理
        /// </summary>
        public async Task OnLoginReq(NetChannel channel, LoginReq req)
        {
            // 鉴权账号信息
            var code = (MessageErrorCode)await AuthLoginTokenAsync(req.AccountId, req.LoginToken);
            if (code != MessageErrorCode.Success)
            {
                channel.SetResponse(req.RpcId, code);
                return;
            }

            // 获取角色id
            var roleId = GetRoleIdByAccountId(req.AccountId);

            // 生成重连票据            
            var reconnectToken = MurmurHash3.Hash($"{roleId}_{DateTime.Now.Ticks}").ToString();
            AddReconnectToken(roleId, reconnectToken);

            // 创建新的session
            AddSession(channel, roleId, reconnectToken);

            // 登陆角色
            code = await LoginRole(channel, roleId, req.AccountId);
            if (code != 0)
            {
                // 登陆失败
                channel.SetResponse(req.RpcId, code);
                return;
            }

            // 返回登录成功
            channel.SetResponse(req.RpcId, new LoginResp
            {
                RoleId = roleId,
                ReconnectToken = reconnectToken,
            });
        }

        /// <summary>
        /// 重连请求处理
        /// </summary>
        public async Task OnReconnectReq(NetChannel channel, ReconnectReq req)
        {
            if (!Comp.RoleIdToReconnectTokenMap.TryGetValue(req.RoleId, out var reconnectToken)
                || reconnectToken != req.ReconnectToken)
            {
                // 重连票据无效
                channel.SetResponse(req.RpcId, MessageErrorCode.ReconnectTokenIsInvalid);
                return;
            }

            // 创建新的session
            AddSession(channel, req.RoleId, req.ReconnectToken);

            // 登陆角色 这里账号id为0, 因为重连的情况下一定已经创建过角色了
            await LoginRole(channel, req.RoleId, 0);

            // 返回重连成功
            channel.SetResponse(req.RpcId, MessageErrorCode.Success);
        }

        #region [登陆流程]

        /// <summary>
        /// 校验账号id和登录票据
        /// </summary>
        private Task<int> AuthLoginTokenAsync(long accountId, string loginToken)
        {
            return new WebVerifyLoginTokenReq
            {
                AccountId = accountId,
                LoginToken = loginToken
            }.Execute().PickCode();
        }

        /// <summary>
        /// 通过账号信息获取角色ID
        /// </summary>
        private long GetRoleIdByAccountId(long accountId)
        {
            // 查询角色账号
            if (State.AccountIdToRoleIdMap.TryGetValue(accountId, out var roleId))
                return roleId;

            // 没有角色，创建新号
            roleId = IdGenerator.GetActorID(ActorType.Role);
            State.AccountIdToRoleIdMap[accountId] = roleId;

            Log.Info("创建新号:" + roleId);
            return roleId;
        }

        /// <summary>
        /// 添加重连票据
        /// </summary>
        private void AddReconnectToken(long roleId, string reconnectToken)
        {
            Comp.RoleIdToReconnectTokenMap[roleId] = reconnectToken;
        }

        /// <summary>
        /// 创建会话并返回重连票据
        /// </summary>
        private void AddSession(NetChannel channel, long roleId, string reconnectToken)
        {
            // 添加到session
            var session = new Session
            {
                Id = roleId,
                Time = DateTime.Now,
                Channel = channel,
                Sign = reconnectToken,
            };

            SessionManager.Add(session);
        }

        /// <summary>
        /// 登陆角色
        /// </summary>
        private async Task<MessageErrorCode> LoginRole(NetChannel channel, long roleId, long accountId)
        {
            // 登陆流程
            var roleComp = await ActorMgr.GetCompAgent<RoleCompAgent>(roleId);

            // 从登录线程-->调用Role线程 所以需要入队
            var code = await roleComp.LoginRole(channel, accountId);
            if (code != 0)
                return code;

            // 加入在线玩家
            var serverComp = await ActorMgr.GetCompAgent<ServerCompAgent>();
            await serverComp.AddOnlineRole(roleId);

            return 0;
        }

        #endregion
    }
}